/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { DfuBaseService } from "../DfuBaseService"
import { LegacyDfuError } from "./LegacyDfuError"
import { SecureDfuError } from "./SecureDfuError"

export class GattError {
  // Starts at line 106 of gatt_api.h file
  /**
   * Converts the connection status given by the {@link android.bluetooth.BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} to error name.
   * @param error the status number
   * @return the error name as stated in the gatt_api.h file
   */
  public static parseConnectionError(error: number): string {
    switch (error) {
      case 0:
        return "SUCCESS";
      case 0x01:
        return "GATT CONN L2C FAILURE";
      case 0x08:
        return "GATT CONN TIMEOUT";
      case 0x13:
        return "GATT CONN TERMINATE PEER USER";
      case 0x16:
        return "GATT CONN TERMINATE LOCAL HOST";
      case 0x3E:
        return "GATT CONN FAIL ESTABLISH";
      case 0x22:
        return "GATT CONN LMP TIMEOUT";
      case 0x0100:
        return "GATT CONN CANCEL ";
      case 0x0085:
        return "GATT ERROR"; // Device not reachable
      default:
        return "UNKNOWN (" + error + ")";
    }
  }

  // Starts at line 29 of the gatt_api.h file
  /**
   * Converts the bluetooth communication status given by other BluetoothGattCallbacks to error name. It also parses the DFU errors.
   * @param error the status number
   * @return the error name as stated in the gatt_api.h file
   */
  public static parse(error: number): string {
    switch (error) {
      case 0x0001:
        return "GATT INVALID HANDLE";
      case 0x0002:
        return "GATT READ NOT PERMIT";
      case 0x0003:
        return "GATT WRITE NOT PERMIT";
      case 0x0004:
        return "GATT INVALID PDU";
      case 0x0005:
        return "GATT INSUF AUTHENTICATION";
      case 0x0006:
        return "GATT REQ NOT SUPPORTED";
      case 0x0007:
        return "GATT INVALID OFFSET";
      case 0x0008:
        return "GATT INSUF AUTHORIZATION";
      case 0x0009:
        return "GATT PREPARE Q FULL";
      case 0x000a:
        return "GATT NOT FOUND";
      case 0x000b:
        return "GATT NOT LONG";
      case 0x000c:
        return "GATT INSUF KEY SIZE";
      case 0x000d:
        return "GATT INVALID ATTR LEN";
      case 0x000e:
        return "GATT ERR UNLIKELY";
      case 0x000f:
        return "GATT INSUF ENCRYPTION";
      case 0x0010:
        return "GATT UNSUPPORT GRP TYPE";
      case 0x0011:
        return "GATT INSUF RESOURCE";
      case 0x001A:
        return "HCI ERROR UNSUPPORTED REMOTE FEATURE";
      case 0x001E:
        return "HCI ERROR INVALID LMP PARAM";
      case 0x0022:
        return "GATT CONN LMP TIMEOUT";
      case 0x002A:
        return "HCI ERROR DIFF TRANSACTION COLLISION";
      case 0x003A:
        return "GATT CONTROLLER BUSY";
      case 0x003B:
        return "GATT UNACCEPT CONN INTERVAL";
      case 0x0087:
        return "GATT ILLEGAL PARAMETER";
      case 0x0080:
        return "GATT NO RESOURCES";
      case 0x0081:
        return "GATT INTERNAL ERROR";
      case 0x0082:
        return "GATT WRONG STATE";
      case 0x0083:
        return "GATT DB FULL";
      case 0x0084:
        return "GATT BUSY";
      case 0x0085:
        return "GATT ERROR";
      case 0x0086:
        return "GATT CMD STARTED";
      case 0x0088:
        return "GATT PENDING";
      case 0x0089:
        return "GATT AUTH FAIL";
      case 0x008a:
        return "GATT MORE";
      case 0x008b:
        return "GATT INVALID CFG";
      case 0x008c:
        return "GATT SERVICE STARTED";
      case 0x008d:
        return "GATT ENCRYPTED NO MITM";
      case 0x008e:
        return "GATT NOT ENCRYPTED";
      case 0x008f:
        return "GATT CONGESTED";
      case 0x00FD:
        return "GATT CCCD CFG ERROR";
      case 0x00FE:
        return "GATT PROCEDURE IN PROGRESS";
      case 0x00FF:
        return "GATT VALUE OUT OF RANGE";
      case 0x0101:
        return "TOO MANY OPEN CONNECTIONS";
      case DfuBaseService.ERROR_DEVICE_DISCONNECTED:
        return "DFU DEVICE DISCONNECTED";
      case DfuBaseService.ERROR_FILE_NOT_FOUND:
        return "DFU FILE NOT FOUND";
      case DfuBaseService.ERROR_FILE_ERROR:
        return "DFU FILE ERROR";
      case DfuBaseService.ERROR_FILE_INVALID:
        return "DFU NOT A VALID HEX FILE";
      case DfuBaseService.ERROR_FILE_IO_EXCEPTION:
        return "DFU IO EXCEPTION";
      case DfuBaseService.ERROR_SERVICE_DISCOVERY_NOT_STARTED:
        return "DFU SERVICE DISCOVERY NOT STARTED";
      case DfuBaseService.ERROR_SERVICE_NOT_FOUND:
        return "DFU CHARACTERISTICS NOT FOUND";
      case DfuBaseService.ERROR_INVALID_RESPONSE:
        return "DFU INVALID RESPONSE";
      case DfuBaseService.ERROR_FILE_TYPE_UNSUPPORTED:
        return "DFU FILE TYPE NOT SUPPORTED";
      case DfuBaseService.ERROR_BLUETOOTH_DISABLED:
        return "BLUETOOTH ADAPTER DISABLED";
      case DfuBaseService.ERROR_INIT_PACKET_REQUIRED:
        return "DFU INIT PACKET REQUIRED";
      case DfuBaseService.ERROR_FILE_SIZE_INVALID:
        return "DFU INIT PACKET REQUIRED";
      case DfuBaseService.ERROR_CRC_ERROR:
        return "DFU CRC ERROR";
      case DfuBaseService.ERROR_DEVICE_NOT_BONDED:
        return "DFU DEVICE NOT BONDED";
      default:
        return "UNKNOWN (" + error + ")";
    }
  }

  public static parseDfuRemoteError(error: number): string {
    switch (error & (DfuBaseService.ERROR_REMOTE_TYPE_LEGACY | DfuBaseService.ERROR_REMOTE_TYPE_SECURE | DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | DfuBaseService.ERROR_REMOTE_TYPE_SECURE_BUTTONLESS)) {
      case DfuBaseService.ERROR_REMOTE_TYPE_LEGACY:
        return LegacyDfuError.parse(error);
      case DfuBaseService.ERROR_REMOTE_TYPE_SECURE:
        return SecureDfuError.parse(error);
      case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED:
        return SecureDfuError.parseExtendedError(error);
      case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_BUTTONLESS:
        return SecureDfuError.parseButtonlessError(error);
      default:
        return "UNKNOWN (" + error + ")";
    }
  }
}